import redis
from base_config.mysql_config import MYSQL_NAME
from base_utils.logger import logger


class SeckillService:
    def __init__(self, redis_client: redis.Redis):
        self.redis_client = redis_client
        self.script_sha = None  # 懒加载
        # Lua 脚本 - 原子操作
        self.seckill_script = """
        local stock_key = KEYS[1]
        local user_key = KEYS[2]
        local user_id = ARGV[1]
        local quantity = tonumber(ARGV[2])

        -- 1. 检查库存 key 是否存在
        local stock_exists = redis.call('EXISTS', stock_key)
        if stock_exists == 0 then
            return -2  -- 秒杀未开始
        end

        -- 2. 检查用户是否已经购买
        local has_bought = redis.call('SISMEMBER', user_key, user_id)
        if has_bought == 1 then
            return -1  -- 已经购买过
        end

        -- 3. 检查库存值
        local stock_value = redis.call('GET', stock_key)
        if not stock_value then
            return -2  -- key 存在但值为空，视为未开始
        end

        local current_stock = tonumber(stock_value)
        if current_stock < quantity then
            return -3  -- 活动已结束（库存不够需求）
        end

        -- 4. 扣减库存并记录用户
        redis.call('DECRBY', stock_key, quantity)
        redis.call('SADD', user_key, user_id)

        return current_stock - quantity  -- 返回剩余库存
        """

    def _load_script(self):
        """加载 Lua 脚本"""
        try:
            self.script_sha = self.redis_client.script_load(self.seckill_script)
            logger.debug(f"[Seckill] Lua 脚本加载成功: {self.script_sha}")
        except Exception as e:
            logger.error(f"[Seckill] Lua 脚本加载失败: {e}")
            self.script_sha = None

    def get_keys(self, product_id):
        pref = f"{MYSQL_NAME}"
        stock_key = f"{pref}:stock:{product_id}"
        user_key = f"{pref}:seckill_users:{product_id}"
        return stock_key, user_key

    def init_sec_kill_data(self, product_id, count):
        # 初始化秒杀商品的数据
        stock_key, user_key = self.get_keys(product_id)
        try:
            self.redis_client.set(stock_key, count)
            self.redis_client.delete(user_key)
        except Exception as e:
            logger.exception(e)
            return False
        return True

    def seckill_with_lua(self, product_id, user_id, quantity=1):
        """使用 Lua 脚本实现秒杀（健壮版）"""

        # 参数防御性校验
        if user_id is None:
            return False, "user_id 不能为空"
        try:
            quantity = int(quantity)
            if quantity <= 0:
                return False, "数量必须大于 0"
        except Exception:
            return False, "数量必须是有效整数"

        stock_key, user_key = self.get_keys(product_id)

        try:
            # 确保脚本已加载
            if not self.script_sha:
                self._load_script()

            # 执行脚本
            result = self.redis_client.evalsha(
                self.script_sha, 2, stock_key, user_key, str(user_id), quantity
            )

        except redis.exceptions.NoScriptError:
            # 脚本丢失 fallback
            logger.warning("[Seckill] Lua 脚本丢失，使用 eval 执行并重新加载")
            result = self.redis_client.eval(
                self.seckill_script, 2, stock_key, user_key, str(user_id), quantity
            )
            self._load_script()

        except Exception as e:
            logger.exception(f"[Seckill] 系统错误: {e}")
            return False, f"系统错误: {str(e)}"

        # 处理 Lua 返回结果
        if result == -2:
            return False, "秒杀活动未开始"
        elif result == -1:
            return False, "您已经参与过本次秒杀"
        elif result == -3:
            return False, "秒杀活动已结束"
        elif isinstance(result, int) and result >= 0:
            return True, f"秒杀成功，剩余库存: {result}"
        else:
            return False, f"未知错误，返回码: {result}"
